Skip to content

fix: exempt the half-state patrol's anchor from the stale bot - #15016

Merged
os-steve merged 1 commit into
mainfrom
claude/issue-15002-stale-exempt-anchor
Sep 3, 2026
Merged

fix: exempt the half-state patrol's anchor from the stale bot#15016
os-steve merged 1 commit into
mainfrom
claude/issue-15002-stale-exempt-anchor

Conversation

@os-steve

@os-steve os-steve commented Sep 3, 2026

Copy link
Copy Markdown
Collaborator

Fixes #15002

.github/workflows/stale.yml's exempt-issue-labels list did not include tracking, the only label the half-state patrol's anchor issue (#9857, confirmed against half-state-patrol.yml's own header) carries — so an anchor whose sole protection is the patrol's own heartbeat (its periodic body rewrite) would go stale at 60 days and close 14 days after that once the patrol stopped running, deleting the one artifact whose job is to make that death visible. This PR adds tracking to the exempt-issue-labels value (now 'pinned,security,roadmap,tracking') and a comment line above it recording the reason, touching no other key and no other file (exempt-pr-labels is unchanged). The hotcrm copy of this workflow is out of scope here per the triage comment — it belongs to the repo:hotcrm seam card.

Premises verified on origin/main before editing:

  • exempt-issue-labels: 'pinned,security,roadmap' is at .github/workflows/stale.yml:48 at origin/main 33681eae — confirmed on the branch (still :48 at commit ee370d31, the branch's fork point).
  • The patrol's anchor issue carries tracking and only tracking, by design: half-state-patrol.yml lines 166-167 — "The anchor deliberately carries tracking and NO domain:* label: tracking is in the sweeper's own H13_EXEMPT_LABELS...".
  • The pinned action version is actions/stale@v11.0.0; its action.yml documents exempt-issue-labels (exact spelling) as "The labels that mean an issue is exempt from being marked stale. Separate multiple labels with commas."
  • python3 -c 'import yaml,sys; yaml.safe_load(open(".github/workflows/stale.yml"))' parses clean after the edit.
  • node scripts/pm/check-governed-merges.mjs --test .github/workflows/stale.yml → NOT governed (0 of 1 path hits the register) — ordinary queue landing applies.

Gate table — verification run at head 06e82410e4141b425b4cc3cdb5893de0fc2eed6c (re-derived with node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack --commands .github/workflows/stale.yml, which reproduced exactly this 26-command list, no additions):

Gate Verdict (gate's own line)
check-aggregator-roster.mjs ✓ check-aggregator-roster: 3 aggregator(s) across 2 workflow(s); roster == needs: in both directions, and all 3 required-context aggregate(s) declared.
check-closing-keyword-parity.mjs check-closing-keyword-parity: OK (3 parsers agree on all 9 keywords and both measured separators; sweep found 5 file(s) carrying the grammar across 8175 tracked file(s), all registered).
check-comment-mask-corpus.mjs ✓ comment-mask corpus sweep [scripts/js-comment-mask.mjs]: 5832 files, 0 disagree, 0 unparseable, 47.9s (comparator self-test: 12 cases pass).
check-position-name-fold-loaders.mjs ✓ check-position-name-fold-loaders: ... 4 reference(s): 2 test, 2 declared instrument, 0 loader. (materialisation worklist stays EMPTY)
check-required-contexts.mjs maps ci.yml jobs to all 4 required-context names (Test Core, Dogfood Regression Gate, Build Core, Temporal Conformance (live PG + MySQL)), exit 0
check-self-test-wired.mjs ✓ check-self-test-wired: every one of the 166 script(s) CI runs that ship a --self-test has that self-test run by CI.
check-self-test-workflow-commands.mjs ✓ check-self-test-workflow-commands: no self-test CI runs prints a line the Actions runner would parse as a workflow command.
check-shard-attestation.mjs ✓ check-shard-attestation: 2 aggregate gate(s) count 3 declared leg(s) across 3 attesting job(s).
check-step-collectors.mjs ✓ check-step-collectors: 394 run: steps across 30 workflow(s); 4 step(s) run 2+ independent self-tests, all of them through a collector.
check-whole-set-label-write.mjs 0 undocumented whole-set label writes; 160 uses: pin(s) judged and cleared, exit 0
docs-audit/check-drift-comment.mjs ✓ check-drift-comment: 56 cases pass across 5 fixture diff(s).
pm/ci-failure.mjs --self-test self-test suite passes (exit table / transport-probe assertions all hold), exit 0
check:agent-test-spelling passes on the rule's cleared set, non-vacuity proven by its own --self-test, exit 0
check:declared-population-live ✓ check:declared-population-live — 159 of 204 famil(ies) declare a path population, and every one of them reaches this tree's 8175 tracked file(s).
check:node-version check-node-version: OK (35 setup-node step(s) across 30 workflow(s), all on Node 22).
check:nul-bytes check-nul-bytes: OK (scanned 8168 text file(s) ... no raw ASCII control bytes).
check:pm-dispatch-gates ✓ dispatch-gates self-test: 1288 cases pass.
check:pnpm-acquisition exit 0 (no unrecognised acquisition mechanism surfaced)
check:pnpm-filter-targets ✓ check:pnpm-filter-targets: 142/181 --filter occurrence(s) across 33 file(s) resolve against 79 workspace package(s); ...
check:refd-timer-probe OK check-refd-timer-probe: 5827 source file(s) swept; the process-global timer probe is read ... and nowhere else.
check:required-contexts same 4-context mapping as above, exit 0
check:shard-attestation ✓ check-shard-attestation: 2 aggregate gate(s) count 3 declared leg(s) across 3 attesting job(s).
check:stall-guard-budget check-stall-guard-budget: OK (30 workflow file(s), 53 job(s), 578 step(s), 7 guard-wrapped step(s); every effective cap clears its job budget by at least one stall window).
check:stall-guard-headroom measure-stall-guard-headroom --self-test: 35 assertion(s) passed.
check:watch-hint-literal ✓ check-watch-hint-literal: 48 declaration(s) across 4 rostered name(s) ... no unrostered spelling of the idiom in the tree.
check:workflow-status-functions check-workflow-status-functions: OK (scanned 30 workflow file(s), 53 job(s), 26 job-level if: expression(s); 10 read needs.*.outputs.*, all naming a status function).

All 26/26 exit 0. First attempt (before pnpm install had been run in this worktree) surfaced the gate scripts' own PREREQUISITE NOT MET (exit 3) declarations plus one raw ERR_MODULE_NOT_FOUND — none of those were red gates, they were NOT MEASURED; the table above is the post-install re-run.

skip-changeset: nothing published from any package (workflow-only diff) — label applied additively and read back.


Generated by Claude Code

Add `tracking` to `exempt-issue-labels` in `.github/workflows/stale.yml`
with a comment explaining why: the patrol's anchor issue carries
`tracking` as its only label and stays alive solely through the
patrol's own heartbeat, so without this exemption a dead patrol's
anchor is marked stale at 60 days and closed 14 days later --
removing the one artifact whose job is to make that death visible.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019RfFHiRCSs3JXLK4cwcfox
@claude claude Bot added the skip-changeset PR has no user-facing published change; bypasses the changeset gate label Sep 3, 2026
@os-steve
os-steve marked this pull request as ready for review September 3, 2026 17:59
@os-steve
os-steve enabled auto-merge September 3, 2026 17:59
@os-steve
os-steve added this pull request to the merge queue Sep 3, 2026
Merged via the queue into main with commit b63052d Sep 3, 2026
31 checks passed
@os-steve
os-steve deleted the claude/issue-15002-stale-exempt-anchor branch September 3, 2026 18:37
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ci/cd size/xs skip-changeset PR has no user-facing published change; bypasses the changeset gate

Projects

None yet

2 participants